//@author A0083782W
#include "TECommonFunctions.h"

namespace GetCurrentTimeFunctions {

	ByteInt getCurrentTime (TimeType thisType) {
		using std::time_t;
		using std::tm;
		using std::time;

		time_t t = time(0);
		struct tm now;
		localtime_s (&now, &t);

		switch (thisType) {
		case GetCurrentTimeFunctions::TimeType::SECOND:
			return (now.tm_sec);
			break;
		case GetCurrentTimeFunctions::TimeType::MINUTE:
			return (now.tm_min);
			break;
		case GetCurrentTimeFunctions::TimeType::HOUR:
			return (now.tm_hour);
			break;
		case GetCurrentTimeFunctions::TimeType::DAY:
			return (now.tm_mday);
			break;
		case GetCurrentTimeFunctions::TimeType::MONTH:
			return (now.tm_mon + 1);
			break;
		case GetCurrentTimeFunctions::TimeType::YEAR:
			return (now.tm_year + 1900 - 2000);
			break;
		case GetCurrentTimeFunctions::TimeType::DAYOFWEEK:
			return (now.tm_wday);
			break;
		default:
			return 0;
			break;
		}
	}
};

namespace StringManipulator {

	int splitString (con_str& mainString, const char sepChar[], const pos_int sepCharSize, 
					vector<string>& stringList, vector<pos_int>& indiceList) {

		bool beginOfWord = true;
		bool aftSpecialChar = true;
		const pos_int lenOfmainString = mainString.size ();
		pos_int noOfWords = 0;

		for (pos_int i = 0; i < lenOfmainString; ) {
			if (isEqualChar (mainString[i], sepChar, sepCharSize)) {
				beginOfWord = false;
				aftSpecialChar = true;
			}
			else {
				if (aftSpecialChar) {
					beginOfWord = true;
					aftSpecialChar = false;
				}
				else {
					beginOfWord = false;
				}
			}

			if (beginOfWord) {
				stringList.push_back (copySubString (mainString, sepChar, sepCharSize,i));
				indiceList.push_back (i);
				i += (stringList[noOfWords++].size());
			}
			else {
				i++;
			}
		}
		return noOfWords;
	}

	string copySubString (con_str& mainString, con_chr sepChar[], const pos_int sepCharSize ,pos_int position) {
		string newString = "";
		const pos_int lenOfmainString = mainString.size();

		for(pos_int i = position; i < lenOfmainString; i++ ) {
			if (isEqualChar (mainString[i], sepChar, sepCharSize)) {
				return newString;
			}
			else {
				newString.push_back (mainString[i]);
			}
		}
		return newString;
	}


	bool isEqualChar (con_chr& mainChar, con_chr arrayChar[], const pos_int sepCharSize) {
		for (pos_int i=0; i < sepCharSize; i++) {
			if (mainChar == arrayChar[i]) {
				return true;
			}
		}
		return false;
	}

	bool isCapitalLetter (con_chr& mainChar)
	{
		if (mainChar >= 'A' && mainChar <= 'Z') {
			return true;
		}
		else {
			return false;
		}
	}

	string getString (con_str& mainString, pos_int repeatNum) {
		string result = "";
		for (pos_int i = 0; i < repeatNum; i++) {
			result += mainString;
		}
		return result;
	}

	string getString (con_chr mainChar, pos_int repeatNum) {
		string result = "";
		for (pos_int i = 0; i < repeatNum; i++) {
			result.push_back (mainChar);
		}
		return result;
	}

	string leftAlign (con_str& mainString, pos_int width) {
		string result = mainString;
		if (mainString.size() < width) {
			for (pos_int i = 0; i < width - mainString.size(); i++) {
				result.push_back (' ');
			}
		}
		return result;
	}

	vector<string> splitLines (con_str& mainString, pos_int lineWidth,
		con_chr sepChar[], pos_int sepCharSize) {
			vector<string> result;
			string temp = mainString;
			while (temp != NULL_STRING) {
				if (temp.size() > lineWidth) {
					int i = 0;
					for (i = lineWidth -1; i >=0; i--) {
						if ( isEqualChar (temp[i], sepChar, sepCharSize)) {
							break;
						}
					}
					if (i != -1) {
						result.push_back (temp.substr(0, i+1));
						temp.erase (0, i+1);
					}
					else {
						result.push_back (temp.substr (0, lineWidth ));
						temp.erase (0, lineWidth);
					}
				}
				else {
					result.push_back (temp);
					temp.clear();
				}
			}
			return result;
	}

	void ignoreCase (string* mainString)
	{
		pos_int lenOfString = mainString->size();
		for (pos_int i = 0; i < lenOfString; i++) {
			if ( isCapitalLetter ((*mainString)[i]) ) {
				(*mainString)[i] += ('a' - 'A');
			}
		}
	}

	string ignoreCase (con_str& mainString)
	{
		string secString = mainString;
		ignoreCase (&secString);
		return secString;
	}

	bool isIllegalString (con_str& subString, con_chr sepChar[],const pos_int sepCharSize ) {
		const pos_int lenOfString = subString.size ();
		
		if (lenOfString <=0 ) {
			return true;
		}

		for (pos_int i = 0; i < lenOfString; i++ ) {
			if (isEqualChar (subString[i], sepChar, sepCharSize)) {
				return true;
			}
		}
		return false;
	}

	bool isLegalString (con_str& mainString, con_chr allowedChar[], const pos_int sepCharSize) {
		const pos_int lenOfString = mainString.size();

		if (lenOfString <= 0) {
			return true;
		}
		for (pos_int i = 0; i < lenOfString; i++ ) {
			if (isEqualChar (mainString[i], allowedChar, sepCharSize)) {
				return false;
			}
		}

		return true;
	}

	bool isSubString (con_str& mainString, con_str& subString, 
						pos_int position)
	{
		const pos_int lenOfmainString = mainString.size ();
		const pos_int lenOfsubString = subString.size ();
		
		if ((lenOfmainString - 1 - position) < (lenOfsubString - 1)) {
			return false;
		}

		for (pos_int i = 0; i < lenOfsubString; i++) {
			if (mainString[i + position] != subString[i]) {
				return false;
			}
		}

		return true;
	}

	bool isNumString (con_str& mainString) {
		for (pos_int i = 0; i < mainString.size(); i++) {
			if (mainString[i] < '0' || mainString[i] > '9' ) {
				return false;
			}
		}
		return true;
	}

	bool isEqualString (con_str& mainString, vector<con_str> const& stringList) {
		for (pos_int i = 0; i < stringList.size(); i++) {
			if (mainString == stringList[i]) {
				return true;
			}
		}
		return false;
	}

	bool isEqualString (con_str& mainString, con_str stringList[], const pos_int nSize) {
		for (pos_int i = 0; i < nSize; i++) {
			if (mainString == stringList[i]) {
				return true;
			}
		}
		return false;
	}

	pos_int findNumOfChar (con_str& mainString, con_chr specialChar) {
		pos_int result = 0;
		for (pos_int i = 0; i < mainString.size(); i++) {
			if (mainString[i] == specialChar) {
				result++;
			}
		}
		return result;
	}

	int filterChar (string& mainString, con_chr specChar[], pos_int specCharSize) {
		pos_int result = 0;
		for (int i = 0; i < (int)mainString.size(); i++) {
			if (!isEqualChar(mainString[i], specChar, specCharSize)) {
				mainString.erase (i,1);
				i--;
				result++;
			}
		}
		return result;
	}

	bool cutWordsFromString (con_str& mainString,con_chr sepChar[], const pos_int sepCharSize, vector<string>& stringList) {
		vector<pos_int> beginning;
		vector<pos_int> ending;
		vector<pos_int> sepIndex;
		sepIndex.push_back (0);
		
		bool isInWord = true;
		pos_int nNum = 0;

		if (mainString.size() <= 0) {
			return false;
		}
		for (pos_int i = 0; i < mainString.size(); i++) {
			if (isEqualChar (mainString[i], sepChar, sepCharSize)) {
				nNum++;
				sepIndex.push_back (i);
			}
		}
		sepIndex.push_back (mainString.size());
		for (pos_int i = 0; i < sepIndex.size() - 1; i++ ) {
			beginning.push_back (0);
			ending.push_back (mainString.size()-1);
		}
		for (pos_int i = 1; i < sepIndex.size() - 1; i++ ) {
			ending[i-1] = sepIndex[i] - 1;
			beginning[i] = sepIndex[i] + 1;
		}
		
		for (pos_int i = 0; i < beginning.size(); i++ ) {
			if (beginning[i] > ending[i] ) {
				stringList.push_back (NULL_STRING);
			}
			else {
				stringList.push_back (mainString.substr (beginning[i], ending[i] - beginning[i] + 1));
			}
		}
		return true;
	}

	bool isNullString (con_str& mainString) {
		if (mainString == NULL_STRING) {
			return true;
		}
		else {
			return false;
		}
	}

	int killChar (string& mainString, con_chr specChar) {
		pos_int result = 0;
		for (int i = 0; i < (int)mainString.size(); i++) {
			if (mainString[i] == specChar) {
				mainString.erase (i, 1);
				result++;
				i--;
			}
		}
		return result;
	}

	void capitaliseFirst (string& mainString) {
		if (mainString[0] >= 'a' && mainString[0] <= 'z') {
			mainString[0] -= 'a'-'A';
		}
	}

	string capitaliseFirst (con_str& mainString) {
		string result = mainString;
		if (mainString[0] >= 'a' && mainString[0] <= 'z') {
			result[0] -= 'a'-'A';
		}
		return result;
	}

	bool isEqualInt (const int number, const int numberList[], const int nListMember) {
		for (pos_int i = 0; i < (pos_int)nListMember; i++) {
			if (number == numberList[i]) {
				return true;
			}
		}
		return false;
	}

	pos_int findAndReplace (string& mainString, con_chr targetChar, con_chr replaceChar) {
		pos_int result = 0;
		for (pos_int i = 0; i < mainString.size(); i++ ) {
			if (mainString[i] == targetChar) {
				mainString[i] = replaceChar;
				result++;
			}
		}
		return result;
	}

	string chopString (con_str& mainString, pos_int width) {
		string result = mainString;
		if(mainString.size() > width ) {
			result = mainString.substr(0, width - 3);
			result += "...";
		}
		return result;
	}
};

namespace TimeManipulator {
	int getRandomNumber (int lowerLimit, int upperLimit) {
		static ByteInt counter = 0;
		if (counter == 0) {
			srand ((pos_int)time(nullptr));
		}
		if (counter > 1000) {
			counter = 0;
		}
		counter++;
		return (rand()%(upperLimit-lowerLimit) + lowerLimit);
	}

	bool isLeapYear (ByteInt yearValue) {
		pos_int fullYear = 2000 + yearValue;
		if (fullYear % 100 == 0 ) {
			if (fullYear % 400 == 0) {
				return true;
			}
			else {
				return false;
			}
		}
		else {
			if (fullYear % 4 == 0) {
				return true;
			}
			else {
				return false;
			}
		}
	}
	
	ByteInt getMaxDay(ByteInt year,Month month) {
		switch (month) {
		case Month::UNDEFINED: 
		case Month::JANUARY:
		case Month::MARCH:
		case Month::MAY:
		case Month::JULY:
		case Month::AUGUST:
		case Month::OCTOBER:
		case Month::DECEMBER:
			return MAX_DAY_PLUS;
			break;
		case Month::APRIL:
		case Month::JUNE:
		case Month::SEPTEMBER:
		case Month::NOVEMBER:
			return MAX_DAY;
			break;
		case Month::FEBURARY:
			if (isLeapYear(year) || year == 0) {
				return MAX_FEB_LEAP_DAY;
			}
			else {
				return MAX_FEB_DAY;
			}
			break;
		default:
			return 0;
			break;
		}
	}
};